package com.wsm.util.httpclient.beanpostprocessor;

import com.wsm.util.httpclient.annotation.Request;
import com.wsm.util.httpclient.config.HttpUtilConfig;
import com.wsm.util.httpclient.config.LogConfig;
import com.wsm.util.httpclient.proxy.HttpRequestProxyFactory;
import com.wsm.util.httpclient.register.HttpClientBeanDefinitionRegistrar;
import com.wsm.util.httpclient.util.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Map;

/**
 * @author ：wangshimin
 * @date ：Created in 2021-02-27 下午 12:45
 * @description：
 * @version:
 */
@Slf4j
@Component
public class HttpClientBeanPostProcessor implements ApplicationContextAware, BeanDefinitionRegistryPostProcessor {

    private final String PRE_KEY = "${";

    private final String END_KEY = "}";

    private Environment environment;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.environment = applicationContext.getEnvironment();
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        Map<String, Class<?>> all = HttpClientBeanDefinitionRegistrar.getAll();
        if (CollectionUtils.isEmpty(all)) {
            log.warn("HttpClient-util:scan specified base package no eligible base class was found");
            return;
        }
        LogConfig logConfig = getLogConfig();
        Integer retryCount = getRetryCount();
        all.forEach((clazzName, cls) -> {
            Request annotation = cls.getAnnotation(Request.class);
            if (annotation == null) {
                log.error("HttpClient-util:class {} @Request is not null,check yourself filter", clazzName);
            } else {
                String baseUrl = annotation.url();
                if (baseUrl.length() == 0) {
                    log.error("HttpClient-util:class {} @Request url is not null", clazzName);
                } else {
                    if (baseUrl.startsWith(PRE_KEY)) {
                        baseUrl = environment.getProperty(baseUrl.substring(2, baseUrl.length() - 1));
                        while (baseUrl != null && !baseUrl.endsWith(END_KEY)) {
                            baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
                        }
                    }
                }
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(cls);
                GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
                definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName())
                        .add("logConfig", logConfig)
                        .add("retryCount", retryCount)
                        .add("baseUrl", baseUrl);
                definition.setBeanClass(HttpRequestProxyFactory.class);
                definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
                beanDefinitionRegistry.registerBeanDefinition(clazzName, definition);
            }
        });
        HttpClientBeanDefinitionRegistrar.clean();
        new HttpClientUtil().init(getHttpUtil());
    }

    /**
     * 获取HttpUtilConfig配置
     */
    private HttpUtilConfig getHttpUtil() {
        HttpUtilConfig httpUtilConfig = new HttpUtilConfig();
        httpUtilConfig.setMaxTotal(getIntConfigNotNullDefault("httpclient.util.max-total", httpUtilConfig.getMaxTotal()));
        httpUtilConfig.setValidateAfterInactivity(getIntConfigNotNullDefault("httpclient.util.validate-after-inactivity", httpUtilConfig.getValidateAfterInactivity()));
        httpUtilConfig.setMaxTimeOut(getIntConfigNotNullDefault("httpclient.util.max-time-out", httpUtilConfig.getMaxTimeOut()));
        return httpUtilConfig;
    }

    private int getIntConfigNotNullDefault(String key, int defaultValue) {
        try {
            String tmpKey = environment.getProperty(key);
            return (null != tmpKey && tmpKey.length() > 0) ? Integer.parseInt(tmpKey) : defaultValue;
        } catch (Exception e) {
            log.warn("HttpClient-util:{} no date,default: {}", key, defaultValue);
        }
        return defaultValue;
    }

    private LogConfig getLogConfig() {
        LogConfig logConfig = new LogConfig();
        logConfig.setUrl(getBooleanConfigNotNullDefault("httpclient.log.url", logConfig.getUrl()));
        logConfig.setResponse(getBooleanConfigNotNullDefault("httpclient.log.response", logConfig.getResponse()));
        logConfig.setTime(getBooleanConfigNotNullDefault("httpclient.log.time", logConfig.getTime()));
        return logConfig;
    }

    private int getRetryCount() {
        try {
            String tmpKey = environment.getProperty("httpclient.retry-count");
            return (null != tmpKey && tmpKey.length() > 0) ? Integer.parseInt(tmpKey) : 1;
        } catch (Exception e) {
            log.warn("HttpClient-util:{}no data ,default:1", "httpclient.retry-count");
        }
        return 1;
    }

    private boolean getBooleanConfigNotNullDefault(String key, Boolean defaultValue) {
        try {
            String tmpKey = environment.getProperty(key);
            return (null != tmpKey && tmpKey.length() > 0) ? "true".equals(tmpKey) : defaultValue;
        } catch (Exception e) {
            log.warn("HttpClient-util:{} no date,default:{}", key, defaultValue);
        }
        return defaultValue;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }
}
